#include <iostream>
#include <pthread.h>
#include <unistd.h>
#include <cstdlib>
#include <string>
#include <thread>
#include <time.h>
#include <cstdio>
#include <cassert>
#include <ctime>

using namespace std;
int tickets = 10000;
#define THREAD_NUM 5 // 线程数量

class threadData // 传给线程的数据结构体
{
public:
    threadData(const string &name, pthread_mutex_t *mtx) : tname(name), pmtx(mtx)
    {
    }
    string tname;          // 线程名
    pthread_mutex_t *pmtx; // 锁
};

void *getTickets(void *args)
{
    srand((unsigned long)time(NULL) & 114514 ^ pthread_self());

    threadData *td = (threadData *)args;
    while (true)
    {
        pthread_mutex_lock(td->pmtx); // 加锁
        // 临界区
        if (tickets > 0) // 判断还有票数， 就进行抢票
        {
            printf("%s:%d\n", td->tname.c_str(), tickets);
            tickets--;
            pthread_mutex_unlock(td->pmtx); // 解锁
        }
        else
        {
            pthread_mutex_unlock(td->pmtx); // 解锁
            break;                          // 没票就退出
        }
        usleep(rand() % 1000); // 对抢到的资源进行处理
    }
    delete td; // 线程退出时销毁线程数据结构体
    return NULL;
}

int main()
{
    pthread_mutex_t mtx;
    pthread_mutex_init(&mtx, NULL); // 初始化锁

    pthread_t tid[THREAD_NUM];
    for (int i = 0; i < THREAD_NUM; i++)
    {
        string name = "thread " + to_string(i + 1);
        threadData *td = new threadData(name, &mtx); // 定义传给线程的数据结构体

        pthread_create(tid + i, NULL, getTickets, (void *)td); // 创建线程
    }

    for (int i = 0; i < THREAD_NUM; i++)
    {
        pthread_join(tid[i], NULL); // 等待线程
    }

    pthread_mutex_destroy(&mtx); // 销毁锁
    return 0;
}